#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

#include <psp2/io/devctl.h>
#include <psp2/io/dirent.h>
#include <psp2/io/fcntl.h>
#include <psp2/io/stat.h>

#include "file.h"
#include "utils.h"

#define SCE_ERROR_ERRNO_EEXIST 0x80010011

int HasEndSlash(const char *path)
{
    return path[strlen(path) - 1] == '/';
}

int RemoveEndSlash(char *path)
{
    int len = strlen(path);

    if (path[len - 1] == '/')
    {
        path[len - 1] = '\0';
        return 1;
    }

    return 0;
}

int AddEndSlash(char *path)
{
    int len = strlen(path);
    if (len < MAX_PATH_LENGTH - 2)
    {
        if (path[len - 1] != '/')
        {
            path[len] = '/';
            path[len + 1] = '\0';
            return 1;
        }
    }

    return 0;
}

int ReadFile(const char *file, void *buf, int size)
{
    SceUID fd = sceIoOpen(file, SCE_O_RDONLY, 0);
    if (fd < 0)
        return fd;

    int read = sceIoRead(fd, buf, size);

    sceIoClose(fd);
    return read;
}

int WriteFile(const char *file, const void *buf, int size)
{
    SceUID fd = sceIoOpen(file, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
    if (fd < 0)
        return fd;

    int written = sceIoWrite(fd, buf, size);

    sceIoClose(fd);
    return written;
}

int AllocateReadFile(const char *file, void **buffer)
{
    SceUID fd = sceIoOpen(file, SCE_O_RDONLY, 0);
    if (fd < 0)
        return fd;

    int size = sceIoLseek32(fd, 0, SCE_SEEK_END);
    sceIoLseek32(fd, 0, SCE_SEEK_SET);

    *buffer = malloc(size);
    if (!*buffer)
    {
        sceIoClose(fd);
        return -1;
    }

    int read = sceIoRead(fd, *buffer, size);
    sceIoClose(fd);

    return read;
}

int GetFileSize(const char *file)
{
    SceUID fd = sceIoOpen(file, SCE_O_RDONLY, 0);
    if (fd < 0)
        return fd;

    int fileSize = sceIoLseek(fd, 0, SCE_SEEK_END);

    sceIoClose(fd);
    return fileSize;
}

int CheckFileExist(const char *file)
{
    SceIoStat st;
    if (sceIoGetstat(file, &st) >= 0)
        return SCE_S_ISREG(st.st_mode);
    return 0;
}

int CheckFolderExist(const char *folder)
{
    SceIoStat st;
    if (sceIoGetstat(folder, &st) >= 0)
        return SCE_S_ISDIR(st.st_mode);
    return 0;
}

int CreateFolder(const char *folder)
{
    int ret = 0;

    if (CheckFolderExist(folder))
        return 0;

    int len = strlen(folder);
    if (len <= 0)
        return -1;

    char *buf = malloc(len + 2);
    if (!buf)
        return -1;
    strcpy(buf, folder);
    if (buf[len - 1] != '/')
    {
        buf[len] = '/';
        buf[++len] = '\0';
    }

    char ch;
    int i;
    for (i = 0; i < len; i++)
    {
        if (buf[i] == '/')
        {
            ch = buf[i];
            buf[i] = '\0';
            ret = sceIoMkdir(buf, 0777);
            buf[i] = ch;
        }
    }

    free(buf);
    if (ret == SCE_ERROR_ERRNO_EEXIST)
        ret = 0;
    return ret;
}

char *GetParentDir(const char *path)
{
    int len = strlen(path);
    if (len <= 0)
        return NULL;

    if (path[len - 1] == '/')
        len--;

    int sep = -1;

    int i;
    for (i = len - 1; i >= 0; i--)
    {
        if (path[i] == '/' || path[i] == ':')
        {
            sep = i + 1;
            break;
        }
    }

    if (sep < 0)
        return NULL;

    int new_len = sep;
    if (new_len <= 0)
        return NULL;

    char *res = (char *)malloc(new_len + 1);
    if (!res)
        return NULL;

    strncpy(res, path, new_len);
    res[new_len] = '\0';

    return res;
}

char *GetFileName(const char *path)
{
    int len = strlen(path);
    if (len <= 0)
        return NULL;

    if (path[len - 1] == '/' || path[len - 1] == ':')
        return NULL; // no file

    int sep = -1;

    int i;
    for (i = len - 1; i >= 0; i--)
    {
        if (path[i] == '/' || path[i] == ':')
        {
            sep = i + 1;
            break;
        }
    }

    if (sep < 0)
        return NULL;

    int new_len = len - sep;
    if (new_len <= 0)
        return NULL;

    char *res = (char *)malloc(new_len + 1);
    if (!res)
        return NULL;

    strncpy(res, path + sep, new_len);
    res[new_len] = '\0';

    return res;
}

char *GetBaseName(const char *path)
{
    int len = strlen(path);
    if (len <= 0)
        return NULL;

    int head = 0;
    int sep = len;

    int i;
    for (i = len - 1; i >= 0; i--)
    {
        if (path[i] == '/' || path[i] == ':')
        {
            head = i + 1;
            break;
        }
        else if ((path[i] == '.') && (sep == len))
        {
            sep = i;
        }
    }

    int new_len = sep - head;
    if (new_len <= 0)
        return NULL;

    char *res = (char *)malloc(new_len + 1);
    if (!res)
        return NULL;

    strncpy(res, path + head, new_len);
    res[new_len] = '\0';

    return res;
}
